/*
 * Archivo.cpp
 *
 *  Created on: 18 Apr 2010
 *      Author: osky
 */
#include "Archivo.h"
#include <string.h>

Archivo* Archivo::_instance = NULL;

char* Archivo::name;

unsigned int Archivo::tamanioMaximoBloque = 0;

int Archivo::ultimoBloque=0;

int Archivo::primerBloque = 0;

int Archivo::cantidadBloques = 0;

Archivo::Archivo(char* nombre, const char* modo) {

	this->arch = fopen(nombre, modo);
	if (this->arch) {

		if ((strcmp(modo, "w")==0) || (strcmp(modo,"w+")==0)) {

			char* bitmap = new char[cantidadBloques];

			inicializarCadenas(bitmap, cantidadBloques);

			fwrite((void*) bitmap, sizeof(char), cantidadBloques, this->arch);

			fwrite((void*) &ultimoBloque, sizeof(ultimoBloque), 1, this->arch);
                         
			delete[] bitmap;
		}
		else{
			fseek(this->arch,cantidadBloques,SEEK_SET);

			int file_read = 0;

			file_read = fread((void*)&ultimoBloque, sizeof(ultimoBloque),1, this->arch);

		}
	}
	
	
}

void Archivo::inicializarCadenas(char* cadenaVacia, int size){

	for (int i = 0; i < size; i++) {

				cadenaVacia[i] = 0;
	}


}

void Archivo::setCantidadMaximaBloques(int tamanio){

	cantidadBloques = (tamanio/BITS_POR_BYTE)+1;
	primerBloque = cantidadBloques*sizeof(char) + sizeof(int);

}

int Archivo::getBloqueLibre() {
	int file_read = 0;
	char *bitmap = new char[cantidadBloques];
	fseek(this->arch, 0, SEEK_SET);
	file_read = fread((void*) bitmap, sizeof(char), cantidadBloques, this->arch);

	int i = 0;

	int j = 0;
	char mascara = 1;

	char valorAnd;

	while (j < cantidadBloques) {

		while ((i < BITS_POR_BYTE)) {

			valorAnd = bitmap[j] & mascara;

			if (valorAnd == 0) {

				bitmap[j] = bitmap[j] ^ mascara;

				fseek(this->arch, 0, SEEK_SET);

				fwrite((void*) bitmap, sizeof(char), cantidadBloques, this->arch);

				int numeroBloque = (j * BITS_POR_BYTE) + (i);

				char *Bloque = new char[tamanioMaximoBloque];

				inicializarCadenas(Bloque, tamanioMaximoBloque);

				fseek(this->arch, primerBloque + numeroBloque * tamanioMaximoBloque, SEEK_SET);

				fwrite((void*) Bloque, sizeof(char), tamanioMaximoBloque, this->arch);

				delete[] Bloque;

				delete[] bitmap;
				
				if(numeroBloque>ultimoBloque) 
					{
					ultimoBloque=numeroBloque;
					fwrite((void*)&ultimoBloque, sizeof(ultimoBloque),1,this->arch);
					}
				return numeroBloque;

			} else {

				mascara <<= 1;
				i++;

			}

		}
		j++;
		i = 0;
		mascara = 1;
	}
	return false;
}

void Archivo::borrarBloque(int numeroBloque) {

	int mascara = 1;

	int posicionBitmap = numeroBloque / BITS_POR_BYTE;

	int posicionBit = numeroBloque - posicionBitmap * BITS_POR_BYTE;

	int file_read = 0;

	mascara <<= posicionBit;

	mascara = ~mascara;

	char* bitmap = new char[cantidadBloques];

	fseek(this->arch, 0, SEEK_SET);

	file_read = fread((void*) bitmap, sizeof(char), cantidadBloques, this->arch);

	bitmap[posicionBitmap] = bitmap[posicionBitmap] & mascara;

	fseek(this->arch, 0, SEEK_SET);

	fwrite((void*) bitmap, sizeof(char), cantidadBloques, this->arch);

	delete [] bitmap;
}

Archivo* Archivo::getInstance(const char* modo) {

	if (modo) {

		if (_instance!=NULL){
			delete _instance;
		}
		_instance = new Archivo(name, modo);
		if (_instance->arch == NULL) {
			delete _instance;
			_instance = NULL;
			return NULL;
		}
		return _instance;

	} else {

		if (!_instance) {
			_instance = new Archivo(name, "w+");
		}

	}
	return _instance;
}

void Archivo::setTamanioBloque(int tamanioBloque) {

	tamanioMaximoBloque = tamanioBloque;

}

void Archivo::setNombre(const char* nombre) {

	name = const_cast<char*> (nombre);

}
void Archivo::write(void *bloque, int numeroBloque) {

	int posicion = numeroBloque * tamanioMaximoBloque;

	fseek(this->arch, primerBloque + posicion, SEEK_SET);

	fwrite((void*) (bloque), sizeof(char), tamanioMaximoBloque, this->arch);

	if (numeroBloque > ultimoBloque){

		ultimoBloque = numeroBloque;

		fseek(this->arch,cantidadBloques,SEEK_SET);
		fwrite((void*)&ultimoBloque,sizeof(ultimoBloque),1,this->arch);
	}

}

void Archivo::read(void* bloque, int numeroBloque) {

	int posicion = numeroBloque * tamanioMaximoBloque;

	fseek(this->arch, primerBloque + posicion, SEEK_SET);

	int file_read = 0;

	file_read = fread(bloque, sizeof(char), tamanioMaximoBloque, this->arch);

}

int Archivo::getUltimoBloque (void)
{

	return ultimoBloque;
}


Archivo::~Archivo() {

	if (this->arch){

		fclose(this->arch);

	}

}

void Archivo::deleteInstance() {

	delete _instance;
	_instance = NULL;
}
